/******************************************************************************/
/*                                                                            */
/*  Copyright (c) 2007-2009: ngi-central.org                                  */
/*  All rights reserved.                                                      */
/*                                                                            */
/******************************************************************************/


/// \file
/// This file implements data structures for moments calculations.


#ifndef __sgl_hu_moments_h__
#define __sgl_hu_moments_h__

#include <sgl/global_settings.h>
#include <sgl/conditions.h>
#include <sgl/scale_invariant_moments.h>
#include <sgl/real_concept.h>
#include <boost/concept_check.hpp>

namespace sgl {


/******************************************************************************/
/*                                                                            */
/* hu_moments                                                                 */
/*                                                                            */
/******************************************************************************/

template <
	/// The type. 
	//! 
	//! This type defaults to SGL_FPTYPE (which in turn defaults to double), but 
	//! any other numeric type is also suitable.
	typename T=SGL_FPTYPE>
/// Class to hold scale invariant moments up to the third order.
//!
//! The Hu moments are invariant under translation, scaling and rotation.
//!
//! The following operations are implemented:
//! operator== : comparison for equality, directly implemented.
//! operator != : comparison for inequality, implemented through 
//! boost::equality_comaparable.
class hu_moments
	: boost::equality_comparable<sgl::hu_moments<T>, 
		sgl::hu_moments<T>
	>
{
	// Only real types qualify for type T. If this line triggers an error,
	// type T is not a real type.
	BOOST_CONCEPT_ASSERT((sgl::real_concept<T>));

public:
	/// The value type.
	typedef T value_type;

	/// Default constructor. 
	//!
	//! Zero initializes the moments.
	hu_moments()
		: phi1_(T())
		, phi2_(T())
		, phi3_(T())
		, phi4_(T())
		, phi5_(T())
		, phi6_(T())
		, phi7_(T())
	{ }

	/// Standard constructor.
	//!
	//! Initializes the moments.
	hu_moments(
		/// First Hu moment.
		T phi1, 
		/// Second Hu moment.
		T phi2,
		/// Third Hu moment.
		T phi3,
		/// Fourth Hu moment.
		T phi4, 
		/// Fifth Hu moment.
		T phi5,
		/// Sixth hu moment.
		T phi6,
		/// Seventh Hu moment.
		T phi7)
		: phi1_(phi1)
		, phi2_(phi2)
		, phi3_(phi3)
		, phi4_(phi4)
		, phi5_(phi5)
		, phi6_(phi6)
		, phi7_(phi7)
	{ }

	/// Constructs Hu moments from scale invariant moments.
	//!
	//! This calculates Hu moments from scale invariant moments.
	hu_moments(
		/// The right hand side.
		sgl::scale_invariant_moments<T> const& r)
		: phi1_(r.calculate_phi1())
		, phi2_(r.calculate_phi2())
		, phi3_(r.calculate_phi3())
		, phi4_(r.calculate_phi4())
		, phi5_(r.calculate_phi5())
		, phi6_(r.calculate_phi6())
		, phi7_(r.calculate_phi7())
	{ }

	/// Constructs a copy.
	hu_moments(
		/// The right hand side.
		sgl::hu_moments<T> const& r)
		: phi1_(r.phi1_)
		, phi2_(r.phi2_)
		, phi3_(r.phi3_)
		, phi4_(r.phi4_)
		, phi5_(r.phi5_)
		, phi6_(r.phi6_)
		, phi7_(r.phi7_)
	{ }

	/// Copy assignment
	sgl::hu_moments<T> & operator =(
		/// The right hand side.
		sgl::hu_moments<T> rhs)
	{
		swap(rhs);
		return *this;
	}

	/// Exchanges two objects.
	void swap(
		/// The other object.
		sgl::hu_moments<T> & rhs)
	{
		std::swap(phi1_, rhs.phi1_);
		std::swap(phi2_, rhs.phi2_);
		std::swap(phi3_, rhs.phi3_);
		std::swap(phi4_, rhs.phi4_);
		std::swap(phi5_, rhs.phi5_);
		std::swap(phi6_, rhs.phi6_);
		std::swap(phi7_, rhs.phi7_);
	}

	/// Compare objects for equality.
	//!
	//! This instance is equal to another instance, if its moments are all equal 
	//! to the moments of the other instance.
	//!
	//! Through the use of boost::equality_comparable operator != is also
	//! defined and implemented by calling this operator.
	//!
	//! \return true if equal, false otherwise.
    bool operator ==(
		/// Right hand side.
		sgl::hu_moments<T> const& rhs) const
    {
        return 
			phi1_ == rhs.phi1_ && 
			phi2_ == rhs.phi2_ &&
			phi3_ == rhs.phi3_ && 
			phi4_ == rhs.phi4_ && 
			phi5_ == rhs.phi5_ &&
			phi6_ == rhs.phi6_ &&
			phi7_ == rhs.phi7_;
    }

	/// Access the first Hu moment.
	//!
	//! /return Returns a reference to the first Hu moment.
	T & phi1()
	{
		return phi1_;
	}

	/// Access the first Hu moment.
	//!
	//! /return Returns a const reference to the first Hu moment.
	T const & phi1() const
	{
		return phi1_;
	}

	/// Access the second Hu moment.
	//!
	//! /return Returns a reference to the second Hu moment.
	T & phi2()
	{
		return phi2_;
	}

	/// Access the second Hu moment.
	//!
	//! /return Returns a const reference to the second Hu moment.
	T const & phi2() const
	{
		return phi2_;
	}

	/// Access the third Hu moment.
	//!
	//! /return Returns a reference to the third Hu moment.
	T & phi3()
	{
		return phi3_;
	}

	/// Access the third Hu moment.
	//!
	//! /return Returns a constst reference to the third Hu moment.
	T const & phi3() const
	{
		return phi3_;
	}

	/// Access the fourth Hu moment.
	//!
	//! /return Returns a reference to the fourth Hu moment.
	T & phi4()
	{
		return phi4_;
	}

	/// Access the fourth Hu moment.
	//!
	//! /return Returns a const reference to the fourth Hu moment.
	T const & phi4() const
	{
		return phi4_;
	}

	/// Access the fifth Hu moment.
	//!
	//! /return Returns a reference to the fifth Hu moment.
	T & phi5()
	{
		return phi5_;
	}

	/// Access the fifth Hu moment.
	//!
	//! /return Returns a const reference to the fifth Hu moment.
	T const & phi5() const
	{
		return phi5_;
	}

	/// Access the sixth Hu moment.
	//!
	//! /return Returns a reference to the sixth Hu moment.
	T & phi6()
	{
		return phi6_;
	}

	/// Access the sixth Hu moment.
	//!
	//! /return Returns a const reference to the sixth Hu moment.
	T const & phi6() const
	{
		return phi6_;
	}

	/// Access the seventh Hu moment.
	//!
	//! /return Returns a reference to the seventh Hu moment.
	T & phi7()
	{
		return phi7_;
	}

	/// Access the seventh Hu moment.
	//!
	//! /return Returns a const reference to the seventh Hu moment.
	T const & phi7() const
	{
		return phi7_;
	}

private:
	/// The first Hu moment.
	T phi1_;

	/// The second Hu moment.
	T phi2_;

	/// The third Hu moment.
	T phi3_;

	/// The fourth Hu moment.
	T phi4_;

	/// The fifth Hu moment.
	T phi5_;

	/// The sixth Hu moment.
	T phi6_;

	/// The seventh Hu moment.
	T phi7_;
};


} // namespace sgl

#endif // __sgl_hu_moments_h__
